﻿using System;
using System.Activities.Presentation;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Headsight.BPMN2WF.BPMN.Model;
using Headsight.BPMN2WF.BPMN.Schemas;
using Headsight.BPMN2WF.Transformation;
using Headsight.BPMN2WF.Transformation.BPMN2TransformerMappings;
using Headsight.BPMN2WF.Transformation.BPMN2TransformerMappings.Config;
using Headsight.BPMN2WF.WF.Impl;

namespace Headsight.BPMN2WF.ConversionWizard
{
    public class BPMN2WFViewModel : INotifyPropertyChanged
    {
        public static string xamlTempFile = Path.GetTempPath() + "bpmn2wf.temp";

        public enum WizardStep
        {
            ChooseBpmn,
            ChooseProperties,
            ConversionPreview,
            ConversionFinished
        }

        private string _bpmnFileName;
        public string BpmnFileName
        {
            get { return _bpmnFileName; }
            set
            {
                _bpmnFileName = value;
                NotifyPropertyChanged("BpmnFileName");
            }
        }

        private string _bpmnFileContent;
        public string BpmnFileContent
        {
            get { return _bpmnFileContent; }
            set
            {
                _bpmnFileContent = value;
                NotifyPropertyChanged("BpmnFileContent");
                NotifyPropertyChanged("NextEnabled");
            }
        }

        private string _wf4FileContent;
        public string Wf4FileContent
        {
            get { return _wf4FileContent; }
            set
            {
                _wf4FileContent = value;
                NotifyPropertyChanged("Wf4FileContent");
            }
        }

        private WizardStep _currentStep;
        public WizardStep CurrentStep
        {
            get { return _currentStep; }
            set
            {
                _currentStep = value;
                NotifyPropertyChanged("CurrentStep");
                NotifyPropertyChanged("Step1Active");
                NotifyPropertyChanged("Step2Active");
                NotifyPropertyChanged("Step3Active");
                NotifyPropertyChanged("Step4Active");
                NotifyPropertyChanged("NextButtonText");
                NotifyPropertyChanged("ConversionText");
                NotifyPropertyChanged("NextEnabled");
                NotifyPropertyChanged("PrevEnabled");
                NotifyPropertyChanged("PrevVisible");
            }
        }
        
        public bool Step1Active
        {
            get { return !ErrorActive && CurrentStep == WizardStep.ChooseBpmn; }
        }

        public bool Step2Active
        {
            get { return !ErrorActive && CurrentStep == WizardStep.ChooseProperties; }
        }

        public bool Step3Active
        {
            get { return !ErrorActive && (CurrentStep == WizardStep.ConversionPreview || CurrentStep == WizardStep.ConversionFinished); }
        }

        public bool NextEnabled
        {
            get
            {
                switch (CurrentStep)
                {
                    case WizardStep.ChooseBpmn:
                        return !string.IsNullOrEmpty(BpmnFileContent);
                    case WizardStep.ChooseProperties:
                        if (CurrentTransformator == null) return false;
                        if (CurrentTransformator.FullName == typeof(BPMN2WFTransformationConfig).FullName && string.IsNullOrEmpty(MappingConfiguration))
                            return false;
                        return true;
                    case WizardStep.ConversionPreview:
                        return true;
                    case WizardStep.ConversionFinished:
                        return true;
                }
                return false;
            }
        }

        public bool PrevEnabled
        {
            get
            {
                switch (CurrentStep)
                {
                    case WizardStep.ChooseBpmn:
                        return false;
                    case WizardStep.ChooseProperties:
                        return true;
                    case WizardStep.ConversionPreview:
                        return true;
                    case WizardStep.ConversionFinished:
                        return true;
                }
                return false;
            }
        }

        public bool PrevVisible
        {
            get { return CurrentStep != WizardStep.ChooseBpmn; }
        }

        public string NextButtonText
        {
            get
            {
                if ((CurrentStep == WizardStep.ConversionFinished) ||
                    (CurrentStep == WizardStep.ConversionPreview && !Beautify))
                    return "Finish";
                return "Next";
            }
        }

        public string ConversionText
        {
            get
            {
                if ((CurrentStep == WizardStep.ConversionFinished) ||
                    (CurrentStep == WizardStep.ConversionPreview && !Beautify))
                    return "Conversion Finished";
                return "Conversion Step 1. Click 'next' to finish conversion";
            }
        }

        public void Next()
        {
            if (ErrorActive) ErrorText = string.Empty;

            switch (CurrentStep)
            {
                case WizardStep.ChooseBpmn:
                    CurrentStep = WizardStep.ChooseProperties;
                    break;
                case WizardStep.ChooseProperties:
                    DoConvert();
                    CurrentStep = WizardStep.ConversionPreview;
                    break;
                case WizardStep.ConversionPreview:
                    if (Beautify) DoBeautify();
                    else DoFinish();
                    CurrentStep = WizardStep.ConversionFinished;
                    break;
                case WizardStep.ConversionFinished:
                    DoFinish();
                    break;
            }
        }

        public void Previous()
        {
            if (ErrorActive) ErrorText = string.Empty;

            switch (CurrentStep)
            {
                case WizardStep.ChooseProperties:
                    BpmnFileContent = string.Empty;
                    BpmnFileName = string.Empty;
                    CurrentStep = WizardStep.ChooseBpmn;
                    break;
                case WizardStep.ConversionPreview:
                    NotifyPropertyChanged("CleanWorkflowDesigner");
                    CurrentStep = WizardStep.ChooseProperties;
                    break;
                case WizardStep.ConversionFinished:
                    DoConvert();
                    CurrentStep = WizardStep.ConversionPreview;
                    break;
            }
        }

        private bool _simplify = true;
        public bool Simplify
        {
            get { return _simplify; }
            set
            {
                _simplify = value;
                NotifyPropertyChanged("Simplify");
            }
        }

        private bool _beautify = true;
        public bool Beautify
        {
            get { return _beautify; }
            set
            {
                _beautify = value;
                NotifyPropertyChanged("Beautify");
            }
        }

        private WorkflowDesigner _workflowDesigner;
        public WorkflowDesigner WorkflowDesigner
        {
            get { return _workflowDesigner; }
            set
            {
                _workflowDesigner = value;
                //NotifyPropertyChanged("WorkflowDesigner");
            }
        }

        private bool _closeMe;
        public bool CloseMe
        {
            get { return _closeMe; }
            set
            {
                _closeMe = value;
                NotifyPropertyChanged("CloseMe");
            }
        }

        public List<Converter> TransformatorList
        {
            get
            {
                return
                    new List<Converter>
                        {
                            new Converter { FullName = typeof(BPMN2WFTransformationsSimple).FullName, Name = "Simple Converter" },
                            new Converter { FullName = typeof(BPMN2WFTransformationVNext).FullName, Name = "Advanced Converter" },
                            new Converter { FullName = typeof(BPMN2WFTransformationConfig).FullName, Name = "Conversion via Configuration File" }
                        };
            }
        }

        private Converter _currentTransformator;
        public Converter CurrentTransformator
        {
            get
            {
                return _currentTransformator;
            }
            set
            {
                _currentTransformator = value;
                NotifyPropertyChanged("CurrentTransformator");
                NotifyPropertyChanged("ConfigurationTransformatorSelected");
                NotifyPropertyChanged("NextEnabled");
            }
        }
        
        public bool ConfigurationTransformatorSelected
        {
            get { return (CurrentTransformator != null && CurrentTransformator.FullName == typeof(BPMN2WFTransformationConfig).FullName); }
        }

        private string _mappingConfiguration;
        public string MappingConfiguration
        {
            get { return _mappingConfiguration; }
            set
            {
                _mappingConfiguration = value;
                NotifyPropertyChanged("MappingConfiguration");
                NotifyPropertyChanged("NextEnabled");
            }
        }

        private string _mappingConfigurationFilename;
        public string MappingConfigurationFilename
        {
            get { return _mappingConfigurationFilename; }
            set
            {
                _mappingConfigurationFilename = value;
                NotifyPropertyChanged("MappingConfigurationFilename");
            }
        }

        private string _errorText;
        public string ErrorText
        {
            get { return _errorText; }
            set
            {
                _errorText = value;
                NotifyPropertyChanged("ErrorText");
                NotifyPropertyChanged("ErrorActive");
                NotifyPropertyChanged("Step1Active");
                NotifyPropertyChanged("Step2Active");
                NotifyPropertyChanged("Step3Active");
                NotifyPropertyChanged("Step4Active");
            }
        }

        public bool ErrorActive
        {
            get { return !string.IsNullOrEmpty(ErrorText); }
        }
        
        #region DoWork
        private void DoFinish()
        {
            try
            {
                WorkflowDesigner.Flush();
                Wf4FileContent = WorkflowDesigner.Text;
            }
            catch {}

            CloseMe = true;
        }

        private void DoBeautify()
        {
            if (Beautify)
            {
                try
                {
                    var wfBeautifier = new WFBeautifier(WorkflowDesigner);
                    var wd = wfBeautifier.Beautify();

                    var tempFile = xamlTempFile;
                    wd.Save(tempFile);

                    NotifyPropertyChanged("RefreshDesigner");
                }
                catch (Exception ex)
                {
                    ErrorText = ex.Message;
                }
            }
        }

        private void DoConvert()
        {
            try
            {
                var designer = Convert2Wf(BpmnFileContent);
                WorkflowDesigner = designer;
                NotifyPropertyChanged("LoadWorkflowDesigner");
            }
            catch (Exception ex)
            {
                ErrorText = ex.Message;
            }
        }

        private WorkflowDesigner Convert2Wf(string bpmnContent)
        {
            var encoding = new ASCIIEncoding();
            var bytes = encoding.GetBytes(bpmnContent);

            var ser = new XmlSerializer(typeof(tDefinitions));
            var tDefinition = (tDefinitions)ser.Deserialize(new MemoryStream(bytes));

            var bpmn2Wf = BPMN2WFFactory.Create(CreateTransformator(), Simplify, tDefinition);
            var tDefinitions2BPMNFlowNodesBlock = new BPMNFlowNodesBlockFactory();

            var bpmnFlowNodesBlock = tDefinitions2BPMNFlowNodesBlock.CreateBPMNFlowNodesBlock(tDefinition);
            var result = bpmn2Wf.Transform(bpmnFlowNodesBlock);

            return (WorkflowDesigner)result.Model;
        }

        private IBPMN2WFTransformations CreateTransformator()
        {
            if (CurrentTransformator.FullName == typeof(BPMN2WFTransformationConfig).FullName)
            {
                var argTypes = new[] {typeof (XmlDocument)};
                var constructor = typeof (BPMN2WFTransformationConfig).GetConstructor(argTypes);
                var mapping = new XmlDocument();
                mapping.LoadXml(MappingConfiguration);
                var argValues = new[] {mapping};
                return (IBPMN2WFTransformations)constructor.Invoke(argValues);
            }

            var type = AppDomain.CurrentDomain.GetAssemblies()
                          .SelectMany(a => a.GetTypes())
                          .FirstOrDefault(t => t.FullName == CurrentTransformator.FullName);
            return (IBPMN2WFTransformations)Activator.CreateInstance(type);
        }
        #endregion

        #region NotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
    }
}
